package be.novelfaces.component;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.context.FacesContext;
import javax.faces.render.Renderer;

import be.novelfaces.component.util.RenderUtils;
import be.novelfaces.component.util.RenderUtilsFactory;

public abstract class AbstractRenderer<T extends UIComponent> extends Renderer {

	@Override
	public void decode(FacesContext facesContext, UIComponent component) {
		RenderUtils renderUtils = RenderUtilsFactory.getInstance();
		decodeComponent(facesContext, checkParamValidity(facesContext, component, renderUtils));
		if (component instanceof ClientBehaviorHolder
				&& !renderUtils.isDisabled(component)) {
			renderUtils.decodeClientBehaviors(facesContext, component);
		}
	}

	@Override
	public void encodeBegin(FacesContext facesContext, UIComponent component)
			throws IOException {
		encodeBeginComponent(facesContext, checkParamValidity(facesContext, component, RenderUtilsFactory.getInstance()));
	}
	
	@Override
	public void encodeEnd(FacesContext facesContext, UIComponent component)
			throws IOException {
		encodeEndComponent(facesContext, checkParamValidity(facesContext, component, RenderUtilsFactory.getInstance()));
	}
	
	@SuppressWarnings("unchecked")
	private T checkParamValidity(FacesContext facesContext,
			UIComponent component, RenderUtils renderUtils) {
		renderUtils.checkParamValidity(facesContext, component, getComponentClass());
		return (T) component;
	}
	
	protected abstract void decodeComponent(FacesContext facesContext, T component);
	
	protected abstract void encodeBeginComponent(FacesContext facesContext, T component) throws IOException;
	
	protected abstract void encodeEndComponent(FacesContext facesContext, T component) throws IOException;

	protected abstract Class<T> getComponentClass();
}